/*
 * Copyright 2009-2010 by The Regents of the University of California
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may obtain a copy of the License from
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.ucr.cs.dblab.acestore.operators;

import java.nio.ByteBuffer;
import java.util.Random;

import edu.ucr.cs.dblab.acestore.api.INoPrevOperatorFactory;
import edu.ucr.cs.dblab.acestore.api.IOperator;
import edu.ucr.cs.dblab.acestore.api.PageAccessHelper;
import edu.ucr.cs.dblab.acestore.base.ACEContext;
import edu.ucr.cs.dblab.acestore.base.LRUCacheAlgorithm;

/**
 * @author jarodwen
 * @created May 22, 2011
 */
public class DataGeneratorOperatorFactory implements INoPrevOperatorFactory {

    private final int randSeed;

    private final int dimensionality;

    private final int dataSize;
    
    private final float ratio;

    public DataGeneratorOperatorFactory(int randSeed, int dimensionality,
            int dataSize, float ratio) {
        this.randSeed = randSeed;
        this.dimensionality = dimensionality;
        this.dataSize = dataSize;
        this.ratio = ratio;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * edu.ucr.cs.dblab.acestore.api.INoPrevOperatorFactory#createOperator(edu
     * .ucr.cs.dblab.acestore.base.ACEContext)
     */
    @Override
    public IOperator createOperator(final ACEContext ctx) {

        final Random rand = new Random(randSeed);

        return new IOperator() {

            private int recCount;
            private int outPageCount;

            @Override
            public void open() throws Exception {
                recCount = 0;
                outPageCount = 0;
            }

            @Override
            public void getNext(ByteBuffer page) throws Exception {
                page.position(0);
                int recInPage = 0;
                while (recCount < dataSize) {
                    if ((recInPage + 1) * (1 + 2 + 2 * dimensionality + 1)
                            * INTSIZE + 2 * INTSIZE + RESERVED_END <= page
                            .capacity()) {
                        page.putInt(dimensionality + 1);
                        for (int i = 0; i < 1 + dimensionality; i++) {
                            page.putInt((i + 1) * INTSIZE - 1);
                        }
                        for (int i = 0; i < dimensionality; i++) {
                            page.putInt(rand.nextInt((int)(dataSize * ratio)));
                        }
                        page.putInt(rand.nextInt(20));
                        // TODO insert end offset
                        PageAccessHelper.SetRecEndOffset(page, recInPage,
                                page.position() - 1);
                        recInPage++;
                        recCount++;
                    } else {
                        break;
                    }
                }
                outPageCount++;
                PageAccessHelper.SetPageRecCount(page, recInPage);
                if (recCount < dataSize)
                    PageAccessHelper.SetPageReference(page, outPageCount);
                else
                    PageAccessHelper.SetPageReference(page, -1);
            }

            @Override
            public void close() throws Exception {
                // TODO Auto-generated method stub

            }
        };
    }

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        ACEContext ctx = new ACEContext(256, 32, new LRUCacheAlgorithm());
        DataGeneratorOperatorFactory generatorFactory = new DataGeneratorOperatorFactory(
                20110602, 3, 200, (float)0.5);
        IOperator generatorOperator = generatorFactory.createOperator(ctx);

        PagePrintOepratorFactory printerFactory = new PagePrintOepratorFactory();
        IOperator printerOperator = printerFactory.createOperator(ctx,
                generatorOperator);

        ByteBuffer page = ByteBuffer.wrap(new byte[ctx.pageSize]);

        printerOperator.open();
        printerOperator.getNext(page);
        printerOperator.close();
    }

}
